#pragma once
#include <memory>
#include <thread>
#include <iostream>
#include <queue>
#include <mutex>
#include <functional>


using namespace std;

class AsyncExecutor
{
public:
	typedef std::function<void()> Functor;
	AsyncExecutor()
		:stop_(false)
	{

	}

	~AsyncExecutor()
	{
		stop_ = true;
		while (!tasks_.empty())
		{
			tasks_.pop();
		}
		condition_.notify_one();
		thread_->join();
	}

	void start()
	{
		thread_ = make_shared<thread>(&AsyncExecutor::run,this);
	}

	void run()
	{
		for (;;)
		{
			Functor task;
			{
				std::unique_lock<std::mutex> lock(this->queue_mutex_);
				this->condition_.wait(lock,
					[this] { return stop_ || !tasks_.empty(); });
				if (stop_)
					return;
				task = std::move(this->tasks_.front());
				tasks_.pop();
			}
			task();
		}
	}

	template<class F, class... Args>
	void  excute( F&& f, Args&&... args)
	{
		auto func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
		excuteFunc(func);
	}

	template<class F>
	void  excuteFunc(F&& f)
	{
		auto func = std::forward<F>(f);

		std::lock_guard<std::mutex> lock(queue_mutex_);

		tasks_.push(func);

		condition_.notify_one();

	}

	
	



	


private:
	std::queue<Functor> tasks_;
	std::mutex queue_mutex_;
	shared_ptr<thread> thread_;
	std::condition_variable condition_;
	bool stop_;
};
